import SockJS from 'sockjs-client/dist/sockjs.min.js';
import chatApi from './api/chat';
import type { IObject } from './api/types';

import { Client } from '@stomp/stompjs';

import mitt from 'mitt';
import { MessageType } from './types';

import messageAudio from './audiofile/message.mp3';

let stompClient: Client;
let soketurl: string = '';
//定义消息订阅列表
type subInfo = {
  path: string;
  subscription: any;
};

//保存当前已订阅的信息
const subscribedList: subInfo[] = [];
let username: string = '';
let corpId: string = '';
let workGroupName: string = '';
let alongData: string = '';
let fromClient: string = 'web';
let baseURL: string = '';

const checkMsg: string[] = [
  MessageType.MESSAGE_TEXT,
  MessageType.MESSAGE_IMAGE,
  MessageType.MESSAGE_VOICE,
  MessageType.MESSAGE_VIDEO,
  MessageType.MESSAGE_FILE,
  MessageType.MESSAGE_GOODS,
  MessageType.MESSAGE_ORDER,
  MessageType.MESSAGE_CARD,
  MessageType.MESSAGE_LINK
];

// 创建一个新的 emitter 实例
export const globalEmitter = mitt();

/**
 * 当前 socket 连接状态
 */
let isConnected: boolean = false;

let muteFlag: boolean = false;
let initLock: boolean = false;

class UniChat {
  constructor() {}

  initParams(params: IObject) {
    console.log('initParams params', params);
    if (params.baseURL && params.socketUrl) {
      chatApi.setBaseUrl(params.baseURL);
      baseURL = params.baseURL;
      soketurl = `${params.socketUrl}/stomp?access_token=`;
    }
  }

  /**
   * 校验初始化参数
   * @returns
   */
  validateInitParams() {
    return baseURL && soketurl;
  }

  /**
   * 设置当前请求的信息
   * @param _workGroupName
   * @param _alongData
   * @param _fromClient
   */
  setCurrentRequestInfo(_workGroupName: string, _alongData?: string, _fromClient?: string) {
    workGroupName = _workGroupName;
    _alongData && (alongData = _alongData);
    _fromClient && (fromClient = _fromClient);
  }

  /**
   * 注册用户
   * 注意：当存在用户直接返回，密码无效。
   * @param params
   * @returns
   */
  createUser(params: IObject) {
    if (!this.validateInitParams()) {
      return Promise.reject({ code: 9002, msg: '未初始化参数' });
    }
    return new Promise((resolve, reject) => {
      chatApi
        .createUser(params.corpId, params.userName, params.password, params.nickName)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          console.log('用户注册失败', err);
          reject(err);
        });
    });
  }

  userLogin(params: IObject) {
    const _that = this;
    if (!this.validateInitParams()) {
      return Promise.reject({ code: 9002, msg: '未初始化参数' });
    }
    if (!params || !params.userName || !params.password) {
      return Promise.reject({ code: 9001, msg: '参数错误' });
    }
    if (!params.userName.startsWith('visitor_')) {
      return Promise.reject({ code: 9003, msg: '用户名格式错误' });
    }
    return new Promise((resolve, reject) => {
      chatApi
        .userLogin(params)
        .then((res: any) => {
          if (res) {
            //保存登录数据
            localStorage.setItem('uni_chat_access_token', res.access_token);
            username = params.userName;
            corpId = params.corpId;
            resolve(res.access_token);
            _that.connection();
          } else {
            reject(res?.msg || '登录失败，请重试！');
          }
        })
        .catch((err) => {
          console.log('登录失败', err);
          reject(err);
        });
    });
  }

  /**
   * 建立socket连接
   */
  connection() {
    const token = localStorage.getItem('uni_chat_access_token');
    if (!token) {
      isConnected = false;
      return;
    }
    if (initLock || isConnected) {
      return;
    }
    initLock = true;
    stompClient = new Client({
      // 设置为空function可禁用debug
      // debug: function (value) {},
      logRawCommunication: true,
      debug: (str: string) => console.log(str),
      // connectionTimeout 必须小于 reconnectDelay 时间，不然会重连成功后再次重连一次
      connectionTimeout: 5000,
      reconnectDelay: 10000,
      heartbeatIncoming: 61000,
      heartbeatOutgoing: 61000
    });

    stompClient.webSocketFactory = () => {
      const _options = { transports: ['websocket', 'xhr-polling'] };
      const url = `${soketurl}${token}`;
      return new SockJS(url, null, _options);
    };

    stompClient.onConnect = () => {
      isConnected = true;
      this.notificationEvents('socketStatusChange', isConnected);
      this.subscribeUser();
    };

    stompClient.onWebSocketClose = () => {
      isConnected = false;
      this.notificationEvents('socketStatusChange', isConnected);
      initLock = false;
      subscribedList.length = 0;
    };
    stompClient.activate();
  }

  /**
   * 主动关闭socket连接
   */
  closeSocket() {
    if (stompClient) {
      stompClient.deactivate();
    }
  }

  activateSocket() {
    if (stompClient) {
      stompClient.activate();
    }
  }

  /**
   * 获取工作组的配置信息
   * @param workGroupName 工作组
   */
  getWorkGroupConfig(workGroupName: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .getWorkGroupConfig(workGroupName)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 获取底部链接信息
   */
  getQuickLink(workGroupName: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .getQuickLink(workGroupName)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 获取信息栏配置
   */
  getInfoBar(workGroupName: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .getInfoBar(workGroupName, fromClient)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 订阅用户个人消息
   */
  subscribeUser() {
    const path = `/topic/user.${username}`;
    if (this.repeatSubscription(path)) {
      return;
    }
    // 订阅消息 ，socket 连接成功时才可订阅
    if (stompClient && isConnected) {
      const subscription = stompClient.subscribe(path, (msg: any) => {
        if (!msg.body || msg.body.trim() == 'SUCCESS') {
          return;
        }
        try {
          const data = JSON.parse(msg.body);
          if (data?.messageType) {
            if (
              data.messageType == MessageType.NOTIFICATION_OFFLINE_MESSAGE_VISITOR_ACCEPT ||
              data.messageType == MessageType.NOTIFICATION_OFFLINE_ACCEPT ||
              data.messageType == MessageType.NOTIFICATION_SESSION ||
              data.messageType == MessageType.NOTIFICATION_QUEUE_ACCEPT
            ) {
              this.playMessageTip();
              this.subcribeChatSession(data.chatSessionId);
            }
            this.notificationEvents('receiveChatMessage', data);
          }
        } catch (e) {
          console.log('>>>', e);
        }
      });
      subscribedList.push({ path, subscription });
    }
  }

  /**
   * 订阅room消息
   */
  subscribeRoom(roomName: string) {
    const path = `/topic/video.${roomName}`;
    if (this.repeatSubscription(path)) {
      return;
    }
    // 订阅消息 ，socket 连接成功时才可订阅
    if (stompClient && isConnected) {
      const subscription = stompClient?.subscribe(path, (msg: any) => {
        if (!msg.body || msg.body.trim() == 'SUCCESS') {
          return;
        }
        console.log('收到订阅的room消息', msg.body);
        try {
          const data = JSON.parse(msg.body);
          if (data?.messageType) {
            this.notificationEvents('receiveChatMessage', data);
            switch (data.messageType) {
              case MessageType.NOTIFICATION_VIDEO_AGENT_CLOSE:
              case MessageType.NOTIFICATION_VIDEO_VISITOR_CLOSE:
              case MessageType.NOTIFICATION_VIDEO_AUTO_CLOSE:
                //会话关闭了，取消订阅消息
                this.unsubscribe(`/topic/video.${data.chatSessionId}`);
                break;
            }
          }
        } catch (e) {
          console.log('>>>', e);
        }
      });
      subscribedList.push({ path, subscription });
    }
  }

  /**
   * 订阅聊天会话
   */
  subcribeChatSession(chatSessionId: string) {
    const path = `/topic/visitor.${chatSessionId}`;
    if (this.repeatSubscription(path)) {
      return;
    }
    if (stompClient && isConnected) {
      const subscription = stompClient.subscribe(path, (msg: any) => {
        if (!msg.body || msg.body.trim() == 'SUCCESS') {
          return;
        }
        try {
          const data = JSON.parse(msg.body);
          if (data?.messageType) {
            if (checkMsg.includes(data.messageType) && data.fromUser == username) {
              //自己发送消息通过http接口发送，已经收到反馈 无需再次处理
              return;
            }
            if (
              MessageType.NOTIFICATION_VISITOR_ONLINE == data.messageType ||
              MessageType.NOTIFICATION_VISITOR_LEAVE == data.messageType
            ) {
              //访客上下线消息无需处理
              return;
            }
            this.playMessageTip();
            this.notificationEvents('receiveChatMessage', data);
            switch (data.messageType) {
              case MessageType.NOTIFICATION_AGENT_CLOSE:
              case MessageType.NOTIFICATION_VISITOR_CLOSE:
              case MessageType.NOTIFICATION_AUTO_CLOSE:
              case MessageType.NOTIFICATION_TRANSFER_AGENT_CLOSE:
                //会话关闭了，取消订阅消息
                this.unsubscribe(`/topic/visitor.${chatSessionId}`);
                break;
              case MessageType.NOTIFICATION_TRANSFER_ACCEPT:
                this.unsubscribe(`/topic/visitor.${chatSessionId}`);
                this.subcribeChatSession(data.data.newChatSession.chatSessionId);
                break;
            }
          }
        } catch (e) {
          console.log('>>>', e);
        }
      });
      subscribedList.push({ path, subscription });
    }
  }

  //判断重复订阅
  repeatSubscription(path: string) {
    return subscribedList.some((item) => {
      return item.path == path;
    });
  }

  //取消订阅
  unsubscribe(path: string) {
    for (let i = 0, len = subscribedList.length; i < len; i++) {
      const _obj = subscribedList[i];
      if (_obj.path === path) {
        _obj.subscription.unsubscribe();
        subscribedList.splice(i, 1);
        return;
      }
    }
  }

  /**
   * 发送客服类会话WebSocket实时消息，支持普通消息和预知消息。
   * notification_preview  预知消息
   * @param msg
   */
  sendWebSocketMessage(
    chatSessionId: string,
    messageType: string,
    content: string,
    fileMessage?: any
  ) {
    if (stompClient && isConnected && chatSessionId) {
      stompClient.publish({
        destination: `/app/visitor.${chatSessionId}`,
        body: JSON.stringify({ messageType, content, fromClient, fileMessage })
      });
    }
  }

  /**
   * 发送预知消息
   * @param chatSessionId
   * @param content
   */
  sendPreviewMessage(chatSessionId: string, content: string) {
    this.sendWebSocketMessage(chatSessionId, 'notification_preview', content);
  }

  /**
   * 获取访客端 UI 配置
   */
  getRateConfig(workGroupName: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .rateConfig(workGroupName)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 检查用户是否有存在的会话
   * @returns promise
   */
  checkExistSession(workGroupName: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .checkExistSession(workGroupName)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 获取企业配置
   * @returns promise
   */
  getCorpConfig() {
    return new Promise((resolve, reject) => {
      chatApi
        .getCorpConfig(corpId)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 获取公告消息
   * @param workGroupName  工作组
   */
  getNotice(workGroupName: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .getNotice(workGroupName)
        .then((res: any) => {
          if (res.code == 0) {
            const notice = res.data;
            if (Array.isArray(res)) {
              notice.map((item: any) => {
                item.title = item.content;
              });
              return resolve([notice]);
            } else {
              notice.title = notice.content;
              return resolve([notice]);
            }
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 获取离线消息
   */
  getOfflineMsg() {
    return new Promise((resolve, reject) => {
      chatApi
        .getOfflineMsg(workGroupName)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 获取消息
   * @param workGroupName    工作组
   * @param isHistory  是否查询历史会话
   * @param chatSessionId  当前会话ID，如不查询历史消息时，仅查询当前会话ID对应聊天内容
   * @param firstMessageCreateTime    上翻翻页第一条消息时间
   */
  getChatRecords(querys: IObject) {
    querys.fromClient = fromClient;
    querys.size = querys.size || 5;
    querys.current = querys.current || 1;
    return new Promise((resolve, reject) => {
      chatApi
        .getChatRecords(querys)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 请求访客接入
   * @param workGroupName  工作组
   */
  requestWorkgroup(
    workGroupName: string,
    robotId?: string,
    accessTrackId?: string,
    inviteId?: string
  ) {
    return new Promise((resolve, reject) => {
      chatApi
        .requestWorkgroup(workGroupName, alongData, fromClient, robotId, accessTrackId, inviteId)
        .then((res: any) => {
          this.playMessageTip();
          return resolve(res);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 请求机器人
   */
  requestRobot(workGroupName: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .requestRobot(workGroupName, alongData, fromClient)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 消息发送
   * @param data  消息内容
   */
  sendMessage(data: IObject) {
    data.fromClient = data.fromClient || fromClient;
    data.alongData = data.alongData || alongData;
    data.status = 'sending';
    return new Promise((resolve, reject) => {
      chatApi
        .sendMessage(data)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }
  /**
   * 消息撤回
   * @param messageId  消息id
   */
  withDrawMessage(messageId: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .withDrawMessage(messageId)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 满意度评价
   * @param querys 请求参数
   *
   * rate {
   * -- chatSessionId 会话id
   * -- rate5Type 评价类型 1：系统自动发起评价 2：坐席主动邀请评价 3:访客主动发起评价
   * -- rate 评价星级
   * -- rating 评价内容
   * -- comment 评价内容
   * -- tags 评价标签
   * -- fromClient
   * }
   */
  sendRate(data: IObject) {
    data.fromClient = data.fromClient || fromClient;
    return new Promise((resolve, reject) => {
      chatApi
        .sendRate(data)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 发送离线消息
   * @param data  请求参数
   * @param data.mobile
   * @param data.email
   * @param data.content
   * @param data.workgroupName
   */
  sendleaveMessage(data: IObject) {
    return new Promise((resolve, reject) => {
      chatApi
        .sendleaveMessage(data)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 查询会话是否已评价
   * @param chatSessionId  会话 id
   */
  isRate(chatSessionId: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .isRate(chatSessionId)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 分组查询在线助手
   * @param querys  查询参数
   * -- workGroupName 工作组id
   * -- parentId  问题父id
   * -- page 当前页码
   */
  getCommonQuestion(data: IObject) {
    return new Promise((resolve, reject) => {
      chatApi
        .getCommonQuestion(data)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 获取在线助手回答
   *
   * @param workgroupName
   * @param faqId
   * @param question
   * @param chatSessionId
   */
  getRobotAnswer(
    workgroupName: string,
    questionId: string,
    questionContent: string,
    chatSessionId: string
  ) {
    return new Promise((resolve, reject) => {
      chatApi
        .getRobotAnswer(workgroupName, questionId, questionContent, chatSessionId)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * @desc 文件上传
   * @param { object}  data-参数
   * @param { string}  data.file-文件
   * @param { string}  data.workgroupName-工作组名称
   * @param { string}  data.chatSessionId-会话id
   */
  uploadFile(data: IObject) {
    return new Promise((resolve, reject) => {
      chatApi
        .uploadFile(data)
        .then((res: any) => {
          if (res.code == 0) {
            resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((error) => {
          reject(error);
        });
    });
  }

  /**
   * 访客主动关闭会话
   * @param chatSessionId  会话 id
   */
  closeChat(chatSessionId: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .closeChat(chatSessionId)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   *获取坐席信息
   * @param username 坐席账号
   * @returns
   */
  getAgentInfo(username: string) {
    return new Promise((resolve, reject) => {
      chatApi
        .getAgentInfo(username)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  /**
   * 请求视频
   * @param data 参数
   */
  videoChat(data: any) {
    return new Promise((resolve, reject) => {
      chatApi
        .videoChat(data)
        .then((res: any) => {
          if (res.code == 0) {
            return resolve(res.data);
          } else {
            return reject({ code: res.code, msg: res.message });
          }
        })
        .catch((err: any) => {
          reject(err);
        });
    });
  }

  /**
   * 全局通知
   * @param eventType  事件类型
   * @param data 发送数据
   */
  notificationEvents(eventType: string, data: any) {
    globalEmitter.emit(eventType, data);
  }

  /**
   * @desc 播放提示音
   * @param {string} src -音频地址
   *
   */
  playMessageTip() {
    if (!muteFlag) {
      try {
        const audio = new Audio(messageAudio);
        audio.play().catch((e) => {
          console.log('播放提示音失败', e);
        });
      } catch (e) {
        console.log('播放提示音失败', e);
      }
    }
  }

  toggleMute(isMute: boolean) {
    muteFlag = isMute;
  }

  appointAgent(
    workgroupName: string,
    agentName: string,
    robotId?: string,
    accessTrackId?: string,
    inviteId?: string
  ) {
    return new Promise((resolve, reject) => {
      chatApi
        .appointAgent({
          workgroupName,
          agentName,
          robotId,
          accessTrackId,
          inviteId,
          alongData,
          fromClient
        })
        .then((res: any) => {
          return resolve(res);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }
}

const uniChat = new UniChat();
export default uniChat;
